package Socket;

import java.io.*;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;

import sql.IndexItem;

import ExecuteEngine.Tuple;


public class Client implements Protocol {
	
	JFrame cf;
	Socket sock;
	ObjectInputStream in=null;
	ObjectOutputStream out;
	int UID;
	
	public Client(JFrame cf) throws IOException {
		this.cf = cf;
		
		sock = new Socket("localhost", 1001);
//		in = new ObjectInputStream(sock.getInputStream());
		out = new ObjectOutputStream(sock.getOutputStream());

	}	

/*	private void SendBytes(byte[] bytes) throws IOException {
		if (bytes==null) {
			out.writeInt(0);
			return;
		}
		out.writeInt(bytes.length);
		if (bytes.length!=0)
			out.write(bytes);
	}
*/	
	private void SendString(String s) throws IOException {
		if (s==null) {
			out.writeInt(0);
			return;
		}
		byte[] bytes = s.getBytes();
		out.writeInt(bytes.length);
		if (bytes.length!=0)
			out.write(bytes);
	}

	private byte[] RecvBytes() throws IOException {
		int length = in.readInt();
		if (length == 0)
			return null;
		byte[] bytes = new byte[length];
		in.read(bytes);
		return bytes;
	}

	private String RecvString() throws IOException {
		int length = in.readInt();
		if (length == 0)
			return null;
		byte[] bytes = new byte[length];
		in.read(bytes);
		return new String(bytes);
	}
	public boolean register(String un, String pwd) {
		try {
			out.writeInt(CMD_REGISTER);
			SendString(un);
			SendString(pwd);
			out.flush();
			if (in==null)
				in = new ObjectInputStream(sock.getInputStream());
			int ret = in.readInt();
			if (ret == RET_REGISTER_FAIL)
				return false;
			return true;
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		}
	}
	public boolean login(String un, String pwd) {
		try {
			out.writeInt(CMD_LOGIN);
			SendString(un);
			SendString(pwd);
			out.flush();
			if (in == null)
				in = new ObjectInputStream(sock.getInputStream());
			UID = in.readInt();
			if (UID>0)
				return true;
			return false;
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		}
		
	}

	public int queryExec(String trim) {
		try {
			out.writeInt(CMD_QUERY);
			out.writeInt(UID);
			SendString(trim);
			out.flush();
			int ret = in.readInt();	
			if (ret == RET_QUERY_ERROR) {
				String s = RecvString();
				throw new Abort_Message(s);
			}
			return ret;
		} catch (IOException e) {
			e.printStackTrace();
			return -1;
		}
	}

	public int getOp() {
		try {
			out.writeInt(CMD_GETOP);
			out.writeInt(UID);
			out.flush();
			return in.readInt();
		} catch (IOException e) {
			e.printStackTrace();
			return -1;
		}
	}

	public String getRel() {
		try {
			out.writeInt(CMD_GETREL);
			out.flush();
			return RecvString();
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
	}

	public IndexItem getIndexItem() {
		try {
			out.writeInt(CMD_GETINDEXITEM);
			out.flush();
			byte[] ret = RecvBytes();
			if (ret==null)
				return null;
			return new IndexItem(ret);
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
	}

	public String getView() {
		try {
			out.writeInt(CMD_GETVIEW);
			out.flush();
			return RecvString();
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
	}

	public List<String> getTables() {
		try {
			out.writeInt(CMD_GETTABLES);
			out.writeInt(UID);
			out.flush();
			List<String> tables = new ArrayList<String>();
			int len = in.readInt();
			for (int i=0; i<len; ++i)
				tables.add(RecvString());
			return tables;
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
	}

	public List<IndexItem> getIndexes() {
		try {
			out.writeInt(CMD_GETINDEXES);
			out.writeInt(UID);
			out.flush();
			List<IndexItem> indexes = new ArrayList<IndexItem>();
			int len = in.readInt();
			for (int i=0; i<len; ++i) {
				indexes.add(new IndexItem(RecvBytes()));
			}
			return indexes;
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
	}

	public List<String> getViews() {
		try {
			out.writeInt(CMD_GETVIEWS);
			out.writeInt(UID);
			out.flush();
			List<String> views = new ArrayList<String>();
			int len = in.readInt();
			for (int i=0; i<len; ++i) {
				views.add(RecvString());
			}
			return views;
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
	}

	public void queryOpen() {
		try {
			out.writeInt(CMD_QUERYOPEN);
			out.writeInt(UID);
			out.flush();
		} catch(IOException e) {
			e.printStackTrace();
		}
	}

/*	public boolean queryHasNext() {
		try {
			out.writeInt(CMD_QUERYHASNEXT);
			out.writeInt(UID);
			out.flush();
			if (in.readInt()>0)
				return true;
			return false;
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		}
	}
*/
	public Tuple queryGetNext() {
		try {
			out.writeInt(CMD_QUERYGETNEXT);
			out.writeInt(UID);
			out.flush();
			byte[] s = RecvBytes();
			if (s == null)
				return null;
			return new Tuple(s);
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
	}

	public void queryClose() {
		try {
			out.writeInt(CMD_QUERYCLOSE);
			out.writeInt(UID);
			out.flush();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public List<String> getTitles(String tablename) {
		try {
			out.writeInt(CMD_GETTITLES);
			out.writeInt(UID);
			SendString(tablename);
			out.flush();
			int len = in.readInt();
			List<String> titles = new ArrayList<String>();
			for (int i=0; i<len; ++i)
				titles.add(RecvString());
			return titles;
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
	}

}
